home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Camelot
/
Camelot 084 (1990-10)(Swedish User Group of Amiga)(SE)(PD)[WB].zip
/
Camelot 084 (1990-10)(Swedish User Group of Amiga)(SE)(PD)[WB].adf
/
UUJoin
/
uujoin.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-31
|
9KB
|
364 lines
/*
* uujoin [ -r ] [ {-amiga | -mac | -pc} ] file(s)...
* join and decode Usenet encoded binary files.
*
* Author: Mark R. Rinfret
* Date: 08-15-90
*
* Public Domain - Use as you wish.
*
* Notes: The uudecode portion was adapted from uudecode.c, packaged
* with Matt Dillon's UUCP implementation.
*
* The Macintosh mode simply filters and joins the files. It
* doesn't decode the BinHex format (got a de-binhexer I can
* have?).
*
* The delimiter strings used to extract the encoded segments
* may change over time. Just edit the assignments to the
* string variables "start" and "stop", as appropriate.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <FileScan.h>
#include <functions.h>
extern int unlink(const char *fileName);
extern int errno;
/* single character decode */
#define DEC(c) (((c) - ' ') & 077)
char *versionString =
"uujoin 1.01 - join and decode Usenet encoded binary files.";
int decode(FILE *in, FILE *out);
int outdec(char *p, FILE *f, int n);
int fr(FILE *fd, char *buf, int cnt);
#define AMI 0
#define MAC 1
#define PC 2
int fileCount; /* set by FileScan() */
char **fileNames; /* allocated by FileScan() */
int fileNumber; /* index into fileNames */
char line[256]; /* allows for long Usenet lines */
int machine; /* machine type */
int removeFiles = 0; /* 1 => remove originals */
char tempName[L_tmpnam]; /* temporary file name */
int
DecodeHexFile(void)
{
char newName[128];
char *s;
int status = 0;
/* Eventually, the code to de-binhex the file will be placed here.
* for now, just rename the temp file as <newName>.hex.
*/
/* Use first filename as the base for the new filename. */
strcpy(newName, fileNames[0]);
s = strrchr(newName, '.'); /* Find rightmost period. */
if (s) *s = '\0'; /* Drop current suffix. */
strcat(newName,".hex"); /* Add ".hex" suffix. */
if (! Rename(tempName, newName)) { /* Rename the file. */
status = IoErr();
fprintf(stderr,"Could not rename '%s' to '%s'; error %ld\n",
tempName, newName, (LONG) status);
}
return status;
}
int
DecodeMergedFile(void)
{
char dest[128];
FILE *in = NULL, *out = NULL;
int mode; /* file protection */
in = fopen(tempName, "r");
if (! in ) {
fprintf(stderr,"Could not reopen merged file: '%s'\n", tempName);
exit(1);
}
/* Search for header line */
for (;;) {
if (fgets(line, sizeof line, in) == NULL) {
fprintf(stderr, "No begin line\n");
exit(1);
}
if (strncmp(line, "begin ", 6) == 0)
break;
}
sscanf(line, "begin %o %s", &mode, dest);
/* create output file */
out = fopen(dest, "w");
if (out == NULL) {
perror(dest);
exit(1);
}
decode(in, out);
if (fgets(line, sizeof line, in) == NULL || strcmp(line, "end\n")) {
fprintf(stderr, "No end line\n");
exit(5);
}
fclose(in);
return 0;
}
int
JoinFiles(void)
{
char *fName; /* current file name */
FILE *inFile = NULL;
char *p; /* adjusted line pointer */
char *start, *stop; /* pattern matching strings */
int startLeng, stopLeng; /* pattern lengths */
int status = 0;
FILE *tempFile = NULL;
tmpnam(tempName);
tempFile = fopen(tempName, "w");
if (!tempFile) {
perror(tempName);
status = errno;
goto done;
}
/* Set up pattern strings according to machine type. Patterns are
* matched from beginning of line through number of chars in pattern.
*/
if (machine == MAC) {
start = "---";
stop = "--- end";
}
else if (machine == PC) {
start = "BEGIN";
stop = "END--";
}
else { /* AMIGA */
start = "sed";
stop = "SHAR_EOF";
}
/* Compute the lengths of the match strings. */
startLeng = strlen(start);
stopLeng = strlen(stop);
/* The Amiga binaries are packaged as shar files and therefore have a
* leading 'X' which must be tossed. Other formats (so far) are not
* packed as shar files and thus, the whole line is used.
*/
p = (machine == AMI ? (line + 1) : line);
while (fileNumber < fileCount) {
fName = fileNames[fileNumber]; /* For programming convenience. */
inFile = fopen(fName, "r");
if (! inFile) {
perror(fName);
status = errno;
goto done;
}
/* Attempt to find the start of this file. */
if (startLeng) {
while (1) {
fgets(line, sizeof(line), inFile);
if ( feof(inFile) ) {
eof_err:
fprintf(stderr,"uujoin: unexpected EOF in file '%s'!\n", fName);
status = EOF;
goto done;
}
if (strncmp(start, line, startLeng) == 0)
break; /* We found the beginning. */
}
}
while (1) {
fgets(line, sizeof(line), inFile);
if ( feof(inFile) ) {
if (stopLeng == 0)
break;
else
goto eof_err;
}
if ( (*line != '\n') && (strncmp(stop, line, stopLeng) == 0) )
break; /* We found the end. */
if ( fputs(p, tempFile) ) { /* Write the _adjusted_ line. */
status = EOF;
fprintf(stderr,"uujoin: error writing to temp file '%s'\n",
tempName);
exit(1);
}
}
fclose(inFile);
++fileNumber;
}
done:
if (tempFile) fclose(tempFile);
if (inFile) fclose(inFile);
return status;
}
main(int argc, char **argv)
{
if (argc < 2) {
usage:
puts(versionString);
puts("Usage: uujoin [options] file1 [... filen]");
puts(" where [options] may be:");
puts("\t-amiga -> uuencoded files wrapped with shar");
puts("\t-mac -> Macintosh binhex files (not decoded in this release)");
puts("\t-pc -> uuencoded files enclosed in BEGIN/END pairs");
puts("\t-r -> remove original files when done");
puts("\n\tUnix-style wildcards may be used in file specifications.");
puts("\n\tExample: uujoin -amiga -r program.??");
puts("\n\tMark R. Rinfret, August 1990.");
puts("\tContributed to the public domain.");
exit(1);
}
--argc; /* Skip over program name. */
++argv;
while (**argv == '-') {
if (strcmp(*argv,"-mac") == 0) {
machine = MAC;
bump:
--argc; /* Skip this arg. */
++argv;
}
else if (strcmp(*argv, "-pc") == 0) {
machine = PC;
goto bump;
}
else if (strcmp(*argv,"-amiga") == 0) {
machine = AMI;
goto bump;
}
else if (strcmp(*argv,"-r") == 0) {
removeFiles = 1;
goto bump;
}
else
goto usage;
}
fileNames = FileScan(argv, argc, &fileCount, 1);
if (! fileNames) {
printf("Filename expansion failed - abort!\n");
exit(1);
}
if (JoinFiles()) exit(1); /* Attempt to join files. */
if (machine == MAC) {
if (DecodeHexFile()) exit(1);
}
else {
if (DecodeMergedFile()) exit(1);
}
unlink(tempName);
if (removeFiles) {
while (--fileCount >= 0) {
unlink(fileNames[fileCount]);
}
}
exit(0);
}
/*
* copy from in to out, decoding as you go along.
*/
decode(in, out)
FILE *in;
FILE *out;
{
char buf[80];
char *bp;
int n;
for (;;) {
/* for each input line */
if (fgets(buf, sizeof buf, in) == NULL) {
printf("Short file\n");
exit(10);
}
n = DEC(buf[0]);
if (n <= 0)
break;
bp = &buf[1];
while (n > 0) {
outdec(bp, out, n);
bp += 4;
n -= 3;
}
}
}
/*
* output a group of 3 bytes (4 input characters).
* the input chars are pointed to by p, they are to
* be output to file f. n is used to tell us not to
* output all of them at the end of the file.
*/
outdec(p, f, n)
char *p;
FILE *f;
{
int c1, c2, c3;
c1 = DEC(*p) << 2 | DEC(p[1]) >> 4;
c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
c3 = DEC(p[2]) << 6 | DEC(p[3]);
if (n >= 1)
fputc(c1, f);
if (n >= 2)
fputc(c2, f);
if (n >= 3)
fputc(c3, f);
}
/* fr: like read but stdio */
int
fr(fd, buf, cnt)
FILE *fd;
char *buf;
int cnt;
{
int c, i;
for (i=0; i<cnt; i++) {
c = fgetc(fd);
if (c == EOF)
return(i);
buf[i] = c;
}
return (cnt);
}